using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using TMS.Application.Common.Interface;
using TMS.Application.Configuration;
using TMS.Application.RequestDto;
using TMS.Application.ResponseDto;
using TMS.Domain.Entity;

namespace TMS.Infrastructrue.Identity
{
    public class IdentityService : IIdentityService
    {
        private readonly IConfiguration _configuration;
        private readonly IRepository<StuUsers> _userRepository;
        private readonly IRepository<TeaUsers> _TeauserRepository;
        private readonly IRepository<TMSIdentityUser> _TMSIdentityUser;

        public IdentityService(IRepository<TeaUsers> TeauserRepository, IConfiguration configuration, IRepository<StuUsers> userRepository, IRepository<TMSIdentityUser> TMSIdentityUser)
        {
            _TeauserRepository = TeauserRepository;
            _configuration = configuration;
            _userRepository = userRepository;
            _TMSIdentityUser = TMSIdentityUser;
        }
        public async Task<AppTokenDto> GenerateToken(StuUsers User, TeaUsers teaUsers, bool isTea)
        {

            if (isTea)
            {
                // 生成token，需要用户的id、用户名等信息
                var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
                var claims = new[]
               {
                new Claim("Id",teaUsers!.Id.ToString()),
                new Claim("UserId",teaUsers!.UserId)
                // new Claim("Username",User!.UserName)
            };

                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret));
                var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var securityToken = new JwtSecurityToken(jwtSetting.Issuer, jwtSetting.Audience, claims, expires: DateTime.UtcNow.AddMinutes(jwtSetting.AccessExpiration), signingCredentials: credentials);

                //生成token
                var token = new JwtSecurityTokenHandler().WriteToken(securityToken);
                var refreshToken = GenerateRefreshToken();

                var tmpIdentityUser = new TMSIdentityUser
                {
                    Id = teaUsers.Id,
                    UserId = teaUsers.UserId,
                    RefreshToken = refreshToken,
                    RefreshTokenExpiration = DateTime.UtcNow.AddMinutes(jwtSetting.RefreshExpiration)
                };

                var TMSIdentityUsers = _TMSIdentityUser.Table.Where(x => x.Id == teaUsers.Id).ToList();
                await _TMSIdentityUser.DeleteBulkAsync(TMSIdentityUsers, true);
                await _TMSIdentityUser.AddAsync(tmpIdentityUser);

                return new AppTokenDto
                {
                    AccessToken = token,
                    RefreshToken = refreshToken,
                    IsTea = isTea
                };


            }
            else
            {

                // 生成token，需要用户的id、用户名等信息
                var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
                var claims = new[]
               {
                new Claim("Id",User!.Id.ToString()),
                new Claim("UserId",User!.UserId)
                // new Claim("Username",User!.UserName)
            };

                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret));
                var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var securityToken = new JwtSecurityToken(jwtSetting.Issuer, jwtSetting.Audience, claims, expires: DateTime.UtcNow.AddMinutes(jwtSetting.AccessExpiration), signingCredentials: credentials);

                //生成token
                var token = new JwtSecurityTokenHandler().WriteToken(securityToken);
                var refreshToken = GenerateRefreshToken();

                var tmpIdentityUser = new TMSIdentityUser
                {
                    Id = User.Id,
                    UserId = User.UserId,
                    RefreshToken = refreshToken,
                    RefreshTokenExpiration = DateTime.UtcNow.AddMinutes(jwtSetting.RefreshExpiration)
                };

                var TMSIdentityUsers = _TMSIdentityUser.Table.Where(x => x.Id == User.Id).ToList();
                await _TMSIdentityUser.DeleteBulkAsync(TMSIdentityUsers, true);
                await _TMSIdentityUser.AddAsync(tmpIdentityUser);

                return new AppTokenDto
                {
                    AccessToken = token,
                    RefreshToken = refreshToken,
                    IsTea = isTea
                };

            }

        }

        public async Task<AppTokenDto> RefreshTokenAsync(AppTokenDto appToken)
        {


            // 生成refreToken需要 过期的token和未过期的refreshToken
            var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,

                ValidIssuer = jwtSetting.Issuer,
                ValidAudience = jwtSetting.Audience,
                // ValidAudiences=au,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret))
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(appToken.AccessToken, tokenValidationParameters, out var securityToken);
            if (securityToken is not JwtSecurityToken jwtSecurityToken ||
                !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new SecurityTokenException("token无效");
            }

            // 更简单一些方式
            var userId = principal.FindFirstValue("UserId");

            // var claimIdentity = principal.Identity as ClaimsIdentity;

            // var username = claimIdentity!.FindFirst(x => x.Type == "Username")?.Value;

            // var realName = username == null ? "" : username;

            // 用从token中获得的用户名，从当前认证用户表中获取对应记录
            var user = _TMSIdentityUser.Table.FirstOrDefault(x => x.UserId.Equals(userId));
            if (user == null || user.RefreshToken != appToken.RefreshToken || user.RefreshTokenExpiration <= DateTime.Now)
            {
                throw new Exception("传入的token或者refreshToken无效");
            }

            if (appToken.IsTea)
            {


                var appUser = _TeauserRepository.Table.FirstOrDefault(x => x.UserId == userId);
                var appuser = _userRepository.Table.FirstOrDefault();

                if (appUser != null)
                {
                    return await GenerateToken(appuser,appUser,appToken.IsTea);
                }
                else
                {
                    return new AppTokenDto();
                }

            }else
            {
                 var appUser = _userRepository.Table.FirstOrDefault(x => x.UserId == userId);
                var appuser =  _TeauserRepository.Table.FirstOrDefault();

                if (appUser != null)
                {
                    return await GenerateToken(appUser,appuser,appToken.IsTea);
                }
                else
                {
                    return new AppTokenDto();
                }
            }


        }

        public async Task<AppTokenDto> ValidateUserAsync(UserForAuthDto userForAuthDto)
        {
            if (userForAuthDto.IsTea)
            {

                // 使用传入的用户名和密码，验证用户名和密码是否都对，对则生成token，否则返回一个空token的对象
                var appUser = _TeauserRepository.Table.FirstOrDefault(x => x.UserId.Equals(userForAuthDto.UserId) && x.PassWord.Equals(userForAuthDto.Password));

                var appuser = _userRepository.Table.FirstOrDefault();


                if (appUser != null)
                {
                    var appToken = await this.GenerateToken(appuser, appUser, userForAuthDto.IsTea);
                    return appToken;
                }
                else
                {
                    return new AppTokenDto();
                }
            }
            else
            {

                // 使用传入的用户名和密码，验证用户名和密码是否都对，对则生成token，否则返回一个空token的对象
                var appUser = _userRepository.Table.FirstOrDefault(x => x.UserId.Equals(userForAuthDto.UserId)
                && x.PassWord.Equals(userForAuthDto.Password));


                var appuser = _TeauserRepository.Table.FirstOrDefault();

                if (appUser != null)
                {
                    var appToken = await this.GenerateToken(appUser, appuser, userForAuthDto.IsTea);
                    return appToken;
                }
                else
                {
                    return new AppTokenDto();
                }
            }

        }

        private string GenerateRefreshToken()
        {
            // 创建一个随机的Token用做Refresh Token
            var rndNumber = new byte[32];

            using var rnd = RandomNumberGenerator.Create();
            rnd.GetBytes(rndNumber);

            return Convert.ToBase64String(rndNumber);
        }
    }
}